package cn.fan.utils;

import cn.fan.config.PassJavaJwtProperties;
import cn.fan.constants.RedisConstants;
import cn.fan.constants.TokenConstants;
import cn.fan.redis.TokenRedis;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class PassJavaJwtTokenUtil {

    @Autowired
    private PassJavaJwtProperties jwtProperties;

//    @Autowired
//    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private TokenRedis tokenRedis;

    /**
     *
     */
    public void moveToken(String userId){
        tokenRedis.moveById(userId);
    }

    /**
     * 生成 token 令牌
     *
     * @param userId 用户Id或用户名
     * @return 令token牌
     */

    public Map<String, Object> generateTokenAndRefreshToken(String userId, String username) {
        Map<String, Object> tokenMap = buildToken(userId, username);
        tokenRedis.putById(userId,tokenMap.get(TokenConstants.ACCESS_TOKEN).toString());
//        cacheToken(userId, tokenMap);
        return tokenMap;
    }


    private Map<String, Object> buildToken(String userId, String username) {
        String accessToken = generateToken(userId, username, null);
//        String refreshToken = generateRefreshToken(userId, username, null);
        HashMap<String, Object> tokenMap = new HashMap<>(2);
        tokenMap.put(TokenConstants.ACCESS_TOKEN, accessToken);
        tokenMap.put(TokenConstants.USER_ID,userId);
        tokenMap.put(TokenConstants.USER_NAME,username);
//        tokenMap.put(TokenConstants.REFRESH_TOKEN, refreshToken);
//        tokenMap.put(TokenConstants.EXPIRE_IN, jwtProperties.getExpiration());
        return tokenMap;
    }

    public String generateToken(String userId, String username,
                                Map<String, String> payloads) {
        Map<String, Object> claims = buildClaims(userId, username, payloads);

        return generateToken(claims);
    }

    private Map<String, Object> buildClaims(String userId, String username, Map<String, String> payloads) {
        int payloadSizes = payloads == null? 0 : payloads.size();

        Map<String, Object> claims = new HashMap<>(payloadSizes + 2);
        claims.put("sub", userId);
        claims.put("username", username);
        claims.put("created", new Date());

        if(payloadSizes > 0){
            claims.putAll(payloads);
        }

        return claims;
    }

    /**
     * 生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private String generateToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis()
                + jwtProperties.getExpiration());
        return Jwts.builder().setClaims(claims)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512,
                        jwtProperties.getSecret())
                .compact();
    }

    /**
     * 生成 token 令牌
     *
     * @param userId 用户Id或用户名
     * @param payloads 令牌中携带的附加信息
     * @return 令牌
     */
    public String generateRefreshToken(String userId, String username, Map<String, String> payloads) {
        Map<String, Object> claims = buildClaims(userId, username, payloads);

        return generateRefreshToken(claims);
    }

    /**
     * 生成刷新令牌 refreshToken，有效期是令牌的 2 倍
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private String generateRefreshToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + jwtProperties.getExpiration() * 2);
        return Jwts.builder().setClaims(claims)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret())
                .compact();
    }


//    private void cacheToken(String userId, Map<String, Object> tokenMap) {
//        stringRedisTemplate.opsForHash().put(RedisConstants.JWT_CACHE_KEY + userId, TokenConstants.ACCESS_TOKEN, tokenMap.get(TokenConstants.ACCESS_TOKEN));
//        stringRedisTemplate.opsForHash().put(RedisConstants.JWT_CACHE_KEY + userId, TokenConstants.REFRESH_TOKEN, tokenMap.get(TokenConstants.REFRESH_TOKEN));
//        stringRedisTemplate.expire(userId, jwtProperties.getExpiration() * 2, TimeUnit.MILLISECONDS);
//    }

    public String getUserIdFromRequest(HttpServletRequest request) {
        return request.getHeader(TokenConstants.USER_ID);
    }

}
